/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package drt;

import evaluation.Graph;
import java.util.*;
import logic.Type;
import util.Util;

/**
 *
 * @author phong
 */
public class DRS extends DrtStandAloneExpression {
    
    List<DRSReferent> refs;
    List<DRSCondition> conds;
    
    public DRS() {
        refs = new LinkedList<DRSReferent>();
        conds = new LinkedList<DRSCondition>();
    }
    
    public DRS(List<DRSReferent> refs, List<DRSCondition> conds) {
        this.refs = refs;
        this.conds = conds;
    }
        
    @Override
    public Type getType() {
        return Type.TRUTH_TYPE;
    }

    /*
     * don't use this function
     */
    @Override
    public void setType(Type t) {
    }
    
    public List<DRSReferent> getRefs() {
        return this.refs;
    }
    
    public List<DRSCondition> getConds() {
        return this.conds;
    }
    
    @Override
    public void getRefs(LinkedHashSet<DRSReferent> refs) {
        refs.addAll(this.refs);
    }
    
    @Override
    public void getAllVariables(LinkedHashSet<DrtVariable> vars) {
        vars.addAll(this.refs);
        for (DRSCondition c : this.conds)
            c.getAllVariables(vars);
    }
    
    @Override
    public DRS simplify() {
        List<DRSCondition> newConds = new LinkedList<DRSCondition>();
        for (DRSCondition c : this.conds) {
            newConds.add(c.simplify());
        }
        return new DRS(this.refs, newConds);
    }
    
    @Override
    public DRS replace(DrtVariable var, DrtExpression exp) {
        List<DRSReferent> newRefs = new LinkedList<DRSReferent>();
        for (DRSReferent r : this.refs) {
            if (r.equals(var)) {
                newRefs.add((DRSReferent)exp);
            }
            else 
                newRefs.add(r);
        }
        List<DRSCondition> newConds = new LinkedList<DRSCondition>();
        for (DRSCondition c : this.conds) {
            newConds.add(c.replace(var, exp));
        }
        return new DRS(newRefs, newConds);        
    }
    
    @Override
    public boolean equals(Object other) {
        if (other instanceof DRS) {
            DRS that = (DRS)other;
            
            // alpha-converting
            
            if (this.refs.size() != that.refs.size() || this.conds.size() != that.conds.size())
                return false;
            
            LinkedHashSet<DrtVariable> thisVars = new LinkedHashSet<DrtVariable>();
            this.getAllVariables(thisVars);
            DRS repThat = (DRS)that.alphaConvert(thisVars);
            
            if (repThat == null) return false;
            
            // comparing conds
            Iterator<DRSCondition> thisCondIter = this.conds.iterator();
            Iterator<DRSCondition> thatCondIter = repThat.conds.iterator();
            
            while (thisCondIter.hasNext()) {
                if (!thisCondIter.next().equals(thatCondIter.next()))
                    return false;
            }
            
            return this.refs.equals(repThat.refs);
        }
        else 
            return false;
    }
        
    @Override
    public int hashCode() {
        int hc = 0;
        // note : doesn't take DRSReferents into accout 
//        for (DRSReferent r : this.refs)
//            hc += r.hashCode();
//        hc *= 31;
        for (DRSCondition c : this.conds)
            hc += c.hashCode();
        return hc;
    }
    
    @Override
    public String toString() {
        return "([" + Util.joinToString(refs, ",") + "],[" + Util.joinToString(conds, ",") + "])";
    }
    
    @Override
    public Graph toGraph() {
        Graph g = new Graph();
        
        for (DRSCondition c : conds) {
            Graph gc = c.toGraph();
            g.merge(gc);
            g.getMarks().addAll(gc.getMarks());
        }
        
        return g;
    }
    
    @Override
    public DRS getTemplate(Map<String,String> map) {
        List<DRSCondition> newConds = new LinkedList<DRSCondition>();
        for (DRSCondition c : this.conds) {
            DRSCondition newC = c.getTemplate(map);
            newConds.add(newC);
        }
        return new DRS(this.refs, newConds);
    }
}
